package demo.netty.nio;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

@Slf4j
public class TestByteBuffer {

    public static void main(String[] args) throws IOException {

    }

    private static void test1() {
        //获取输入流，在获取到管道
        URL url = Thread.currentThread().getContextClassLoader().getResource("data.txt");
        assert url != null;
        String file = url.getFile();
        log.info(file);
        try(FileChannel channel = new FileInputStream(file).getChannel()) {
            //设置缓冲区为10个字节的大小
            ByteBuffer byteBuffer = ByteBuffer.allocate(15);
            do {
                //从channel当中读取数据
                int read = channel.read(byteBuffer);
                if (read == -1) {
                    log.info("结束数据读取返回。。。。");
                    return;
                }
                //将byteBuffer切换为读模式
                byteBuffer.flip();
                //判断当前缓冲区中是否还有剩余未读的数据
                while (byteBuffer.hasRemaining()){
                    byte b = byteBuffer.get();
                    log.info("打印数据：{}",(char)b);
                }
                //将其转换为写模式，如果不转换，那么会一只进行读取，因为hasRemaining()方法是根据 position < limit进行判断，转换为写之后，position的位置会被赋值为capacity
                byteBuffer.clear();
            }while (true);
        }  catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 写入数据
     */
    private static void writer() {
        //获取输入流，在获取到管道
        URL url = Thread.currentThread().getContextClassLoader().getResource("data.txt");
        assert url != null;
        String file = url.getFile();
        try(FileChannel channel = new RandomAccessFile(file, "rw").getChannel()) {
            ByteBuffer buffer = StandardCharsets.UTF_8.encode("hello,world");
            int write = channel.write(buffer);
            log.info("写入长度：{}",write);
            test1();
        }  catch (IOException e) {
            e.printStackTrace();
        }

    }


    public static ThreadLocal<Data> dataThreadLocal = new ThreadLocal<>();

    /**
     * 粘包/半包，通过使用 /n分割 模拟网络发送的数据包
     * 1、查询ThreadLocal中还有没有上一次没有读取完的数据
     *      1.1 将上一次未获取完数据跟当前数据进行合并
     *      1.2 开启读模式
     *      1.3 验证 position的位置 跟limit的位置是否相同，如果不同证明 数据没有取完
     * 2、读取数据
     */
    private static void split(ByteBuffer byteBuffer){
        //切换读模式
        Data lastData = dataThreadLocal.get();
        if (Objects.nonNull(lastData)) {
            ByteBuffer lastDataBuffer = lastData.getData();
            ByteBuffer newByteBuffer = ByteBuffer.allocate(byteBuffer.limit() + (lastDataBuffer.limit() - lastDataBuffer.position()));
            while (lastDataBuffer.hasRemaining()){
                newByteBuffer.put(lastDataBuffer.get());
            }
            newByteBuffer.put(byteBuffer);
            newByteBuffer.flip();
            //读取新传入的，将上一次的数据进行合并
            for (int i = 0; i < newByteBuffer.limit(); i++) {
                byte b = newByteBuffer.get(i);
                if ('\n' == b) {
                    int length = i + 1 - newByteBuffer.position();
                    ByteBuffer allocate = ByteBuffer.allocate(length);
                    for (int i1 = 0; i1 < allocate.limit(); i1++) {
                        allocate.put(newByteBuffer.get());
                    }
                    allocate.flip();
                    System.out.println("后续包数据："+StandardCharsets.UTF_8.decode(allocate));
                }
            }
            if (newByteBuffer.position() != newByteBuffer.limit()) {
                //没有截取完的数据，将后面的数据放入
                Data data = new Data(Thread.currentThread().getName(), newByteBuffer);
                dataThreadLocal.set(data);
            }
        }else {
            //将数据按照转义符进行分割
            for (int i = 0; i < byteBuffer.limit() ; i++) {
                //截取数据
                byte b = byteBuffer.get(i);
                if ('\n' == b) {
                    int length = i + 1 - byteBuffer.position();
                    ByteBuffer allocate = ByteBuffer.allocate(length);
                    for (int i1 = 0; i1 < allocate.limit(); i1++) {
                        allocate.put(byteBuffer.get());
                    }
                    allocate.flip();
                    System.out.println("打印数据："+StandardCharsets.UTF_8.decode(allocate));
                }
            }
            if (byteBuffer.position() != byteBuffer.limit()) {
                //没有截取完的数据，将后面的数据放入
                Data data = new Data(Thread.currentThread().getName(), byteBuffer);
                dataThreadLocal.set(data);
            }
        }
    }


    @lombok.Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Data {
        private String thread;
        private ByteBuffer data;
    }

}
